-- Coding Format : UTF-8
-- 「WatchDog.lua 脚本介绍」
-- WatchDog，正如其字面意思，扮演了“看门狗”的角色，负责蹲在大门口，看有没有新玩家过来
-- 玩家通过服务器IP地址+端口号，来接入服务器，而WatchDog就在服务器里一直盯着这个端口看，如果从端口收到请求，就进行处理
local skynet = require "skynet"
local socket = require "skynet.socket"
local CMD = {}
local SOCKET = {}
local gate
local agent = {}

-- 获取所有id
function CMD.getFds()
    local res = {}
    for k, v in pairs(agent) do
        res[#res + 1] = k
    end
    return res
end

-- SOCKET逻辑
-- 新客户端申请接入时调用
function SOCKET.open(fd, addr)
    skynet.error("New client from : " .. addr)

    -- 为新玩家分配一个agent
    agent[fd] = skynet.newservice("agent")

    -- 启动新玩家的agent
    skynet.call(agent[fd], "lua", "start", {
        gate = gate,
        client = fd,
        watchdog = skynet.self()
    })
end

-- 关闭agent
local function close_agent(fd)
    local a = agent[fd]
    skynet.error(">>>>>close_agent>>>>" .. fd)
    agent[fd] = nil
    if a then
        skynet.call(gate, "lua", "kick", fd)
        skynet.send(a, "lua", "disconnect", fd)
    end
end

-- 客户端断开连接
function SOCKET.close(fd)
    print("socket close", fd)
    close_agent(fd)
end

-- 客户端出错
function SOCKET.error(fd, msg)
    print("socket error", fd, msg)
    close_agent(fd)
end

-- 客户端warning
function SOCKET.warning(fd, size)
    -- size K bytes havn't send out in fd
    print("socket warning", fd, size)
end

-- CMD逻辑
-- 服务启动后接收到main发过来的start指令
function CMD.start(conf)
    skynet.call(gate, "lua", "open", conf)
end

skynet.start(function()
    -- 处理外部调用请求
    skynet.dispatch("lua", function(session, source, cmd, subcmd, ...)
        if cmd == "socket" then
            local f = SOCKET[subcmd]
            f(...)
            -- socket api don't need return
        else
            local f = assert(CMD[cmd])
            skynet.ret(skynet.pack(f(subcmd, ...)))
        end
    end)

    -- 启动端口监视器
    gate = skynet.newservice("gate")
end)
